﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Quakk;
using Quakk.Controls;
using Quakk.Twitter;

namespace Quakk.Forms
{
    public partial class MainForm : Form
    {
        private Configuration configuration;
        private readonly TwitterApi twitterApi;
        private Timeline activeTimeline;
        private int selectedTweet;

        public MainForm()
        {
            InitializeComponent();

            configuration = Configuration.LoadConfiguration();
            
            if(configuration == null)
            {
                twitterApi = new TwitterApi();
                DisplayConfigurationForm();
            }
            else
            {
                twitterApi = new TwitterApi
                              {
                                  Username = configuration.Username,
                                  Password = configuration.Password
                              };
            }

            activeTimeline = new MainTimeline(twitterApi);
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            BackColor = Display.BackgroundColour;
            mainPanel.BackColor = Display.BackgroundColour;

            try
            {
                activeTimeline.Load();
            }
            catch (TwitterResponseException ex)
            {
                MessageBox.Show(ex.Message);
            }

            List<Tweet> tweets = activeTimeline.Tweets;
            UpdateTweetPanel(tweets);
        }

        /// <summary>
        /// Resizes all of the TweetPanels to match the new Width of the Form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mainPanel_Resize(object sender, EventArgs e)
        {
            mainPanel.AutoScrollPosition = new Point(0, 0);

            int y = 0;
            for (int i = 0; i < mainPanel.Controls.Count; i++)
            {
                TweetPanel tweetPanel = (TweetPanel) mainPanel.Controls[i];
                tweetPanel.SetWidth(mainPanel.Width - 13);
                tweetPanel.Top = y;
                y += tweetPanel.Height;
            }

            mainPanel.AutoScrollPosition = new Point(0, CumlativeHeight(selectedTweet));
        }

        /// <summary>
        /// Scrolls up and down through the TweetPanels
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyCode == Keys.Up))
            {
                if (selectedTweet > 0 && mainPanel.Controls.Count > 0)
                {
                    selectedTweet--;
                    mainPanel.AutoScrollPosition = new Point(0, CumlativeHeight(selectedTweet));
                }
            }
            if ((e.KeyCode == Keys.Down))
            {
                if (selectedTweet < mainPanel.Controls.Count - 1 && mainPanel.Controls.Count > 0)
                {
                    if (CumlativeHeight(19) - CumlativeHeight(selectedTweet - 1) > mainPanel.ClientRectangle.Height)
                    {
                        selectedTweet++;
                        mainPanel.AutoScrollPosition = new Point(0, CumlativeHeight(selectedTweet));
                    }
                }
            }
        }

        /// <summary>
        /// Updates the local copy of Tweets from Twitter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuItemUpdate_Click(object sender, EventArgs e)
        {
            RefreshTweets();
        }

        /// <summary>
        /// Opens the TweetForm so the user can send a Tweet
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuItemTweet_Click(object sender, EventArgs e)
        {
            if (ValidConfiguration() == false)
            {
                return;
            }

            TweetForm tweetForm = new TweetForm(twitterApi)
                                      {
                                          BackColor = Display.BackgroundColour
                                      };            
            tweetForm.Show();
        }

        private void menuItemConfig_Click(object sender, EventArgs e)
        {
            DisplayConfigurationForm();
        }

        /// <summary>
        /// Exits the application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuItemExit_Click(object sender, EventArgs e)
        {
            Close();
            Application.Exit();
        }

        /// <summary>
        /// Changes the active timeline
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void menuItemTimelineChange(object sender, EventArgs e)
        {
            MenuItem menuItem = (MenuItem) sender;

            switch (menuItem.Text)
            {
                case "Main":
                    activeTimeline = new MainTimeline(twitterApi);
                    break;
                case "Replies":
                    activeTimeline = new ReplyTimeline(twitterApi);
                    break;
                case "Direct Messages":
                    activeTimeline = new DirectMessageTimeline(twitterApi);
                    break;
            }

            Cursor.Current = Cursors.WaitCursor;

            activeTimeline.Load();
            UpdateTweetPanel(activeTimeline.Tweets);

            foreach (MenuItem item in menuItemTimeline.MenuItems)
            {
                item.Checked = false;
            }
            menuItem.Checked = true;

            Cursor.Current = Cursors.Default;

        }

        /// <summary>
        /// Called when the user clicks on a TweetPanel,
        /// Builds and displays a popup menu relevant to that Tweet
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TweetClicked(object sender, EventArgs e)
        {
            TweetPanel clickedTweet = (TweetPanel) sender;

            MenuPanel menuPanel = new MenuPanel(clickedTweet.Tweet)
                                      {
                                          Dock = DockStyle.Fill
                                      };

            menuPanel.Reply += OnReply;
            menuPanel.OpenLink += OnOpenLink;
            menuPanel.ViewPicture += OnViewPicture;

            Controls.Add(menuPanel);
            menuPanel.BringToFront();
            Refresh();
        }

        /// <summary>
        /// Called when the user clicks Reply in the popup menu,
        /// Opens the TweetForm with the recipients address already entered
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected void OnReply(object sender, MenuEventArgs args)
        {
            Controls.Remove((Control)sender);
            Tweet tweet = args.Tweet;

            if (ValidConfiguration() == false)
            {
                return;
            }

            TweetForm tweetForm = new TweetForm(twitterApi)
                                      {
                                          BackColor = Display.BackgroundColour,
                                          TweetText = "@" + tweet.Username + " "
                                      };
            tweetForm.Show();
        }

        /// <summary>
        /// Called when a user clicks Open Link from the popup menu,
        /// Opens the Url in the default browser
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected void OnOpenLink(object sender, MenuEventArgs args)
        {
            Controls.Remove((Control)sender);

            Tweet tweet = args.Tweet;
            string url = tweet.ExtractUrl();

            ProcessStartInfo processStartInfo = new ProcessStartInfo{ FileName = url };
            Process.Start(processStartInfo);
        }

        /// <summary>
        /// Called when a user clicks View Picture from the popup menu,
        /// Downloads the image from TwitPic and displays it
        /// </summary>
        /// <param name="sender">The popup menu</param>
        /// <param name="args"></param>
        protected void OnViewPicture(object sender, MenuEventArgs args)
        {
            const string twitPicPattern = @"src=""(http://s3.amazonaws.com/twitpic/[^""]*)""";

            Cursor.Current = Cursors.WaitCursor;

            // Remove the popup menu
            Controls.Remove((Control)sender);

            Tweet tweet = args.Tweet;
            string url = tweet.ExtractUrl();
            string twitPicHtml = twitterApi.OpenUrl(url);

            // Extract the Url of the image from the Html returned from TwitPic
            Match match = Regex.Match(twitPicHtml, twitPicPattern);
            if(match.Success)
            {
                string imageUrl = match.Groups[1].Value;
                twitterApi.DownloadImage(imageUrl, "TwitPic.jpg");

                Bitmap picture = new Bitmap("TwitPic.jpg");
                ViewPicture viewPicture = new ViewPicture
                                              {
                                                  Picture = picture
                                              };

                Cursor.Current = Cursors.Default;
                viewPicture.ShowDialog();
            }

            Cursor.Current = Cursors.Default;
        }

        /// <summary>
        /// Refreshes the active timeline from Twitter
        /// </summary>
        private void RefreshTweets()
        {
            if (ValidConfiguration() == false)
            {
                return;
            }

            Cursor.Current = Cursors.WaitCursor;

            try
            {
                activeTimeline.Update();
            }
            catch (TwitterResponseException ex)
            {
                MessageBox.Show(ex.Message);
                Cursor.Current = Cursors.Default;
                return;
            }

            List<Tweet> tweets = activeTimeline.Tweets;

            UpdateTweetPanel(tweets);

            // Any images that aren't available locally
            // are downloaded in a separate thread
            ThreadStart threadStart = activeTimeline.DownloadMissingImages;
            Thread thread = new Thread(threadStart);
            thread.Start();

            Cursor.Current = Cursors.Default;
        }

        /// <summary>
        /// Checks if there is a valid Configuration, if not it prompts the user to enter one
        /// </summary>
        /// <returns></returns>
        private bool ValidConfiguration()
        {
            if (configuration == null)
            {
                DialogResult result =
                    MessageBox.Show("You have not entered your TwitterApi login details, would you like to do this now?",
                                    "Quakk", MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                                    MessageBoxDefaultButton.Button1);
                if (result == DialogResult.No)
                {
                    return false;
                }

                DisplayConfigurationForm();
                if (configuration == null)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Updates the Main Panel with the Tweets provided
        /// </summary>
        /// <param name="tweets">The Tweets to display</param>
        private void UpdateTweetPanel(IEnumerable<Tweet> tweets)
        {
            if (tweets != null)
            {
                RemoveTweetsFromPanel();
                mainPanel.AutoScrollPosition = new Point(0, 0);
                selectedTweet = 0;

                int top = 0;
                foreach (Tweet tweet in tweets)
                {
                    TweetPanel panel = new TweetPanel(this, tweet)
                    {
                        Left = 0,
                        Top = top
                    };
                    panel.SetWidth(mainPanel.Width - 13);
                    panel.Click += TweetClicked;
                    mainPanel.Controls.Add(panel);
                    top += panel.Height;
                }
            }
        }

        /// <summary>
        /// Clears all TweetPanels from the Main Panel
        /// </summary>
        private void RemoveTweetsFromPanel()
        {
            foreach (Control control in mainPanel.Controls)
            {
                control.Dispose();
            }
            mainPanel.Controls.Clear();
        }

        /// <summary>
        /// Displays the Configuration Form
        /// </summary>
        private void DisplayConfigurationForm()
        {
            ConfigForm configForm = new ConfigForm(configuration);
            configForm.ShowDialog();
            configuration = configForm.Configuration;

            if (configuration != null)
            {
                configuration.Save();
                twitterApi.Username = configuration.Username;
                twitterApi.Password = configuration.Password;
            }
        }

        /// <summary>
        /// Return the culmative height of the TweetPanels
        /// </summary>
        /// <param name="index">The tweet to start counting from</param>
        /// <returns>The height</returns>
        private int CumlativeHeight(int index)
        {
            int height = 0;
            if (index < mainPanel.Controls.Count)
            {
                for (int i = 0; i < index; i++)
                {
                    height += mainPanel.Controls[i].Height;
                }
            }
            return height;
        }
    }
}